package mylittleinvestigations.FieldCharacters;

import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import mylittleinvestigations.Animation;
import mylittleinvestigations.CaseInformation.Case;
import mylittleinvestigations.CaseInformation.CaseParseException;
import mylittleinvestigations.CaseInformation.CaseXmlReader;
import mylittleinvestigations.CaseInformation.CaseXmlWriter;
import mylittleinvestigations.Collisions.CollisionParameter;
import mylittleinvestigations.Collisions.HitBox;
import mylittleinvestigations.Condition;
import mylittleinvestigations.Encounter;
import mylittleinvestigations.FieldCutscene;
import mylittleinvestigations.HeightMaps.HeightMap;
import mylittleinvestigations.InteractiveElement;
import mylittleinvestigations.Location;
import mylittleinvestigations.MouseHelper;
import mylittleinvestigations.Vector2;
import mylittleinvestigations.ZOrderableObject;
import org.newdawn.slick.*;
import org.newdawn.slick.geom.*;

public class FieldCharacter implements InteractiveElement, ZOrderableObject
{
    private String[] characterStandingAnimationIds;
    private String[] characterWalkingAnimationIds;
    private String[] characterRunningAnimationIds;

    private Animation[] characterStandingAnimations;
    private Animation[] characterWalkingAnimations;
    private Animation[] characterRunningAnimations;

    private boolean isBegun;
    private FieldCharacterState state;
    private Animation currentAnimation;

    private Encounter clickEncounter;
    private FieldCutscene clickCutscene;
    
    private int extraHeight;

    public FieldCharacter(String characterId, String characterName, String[] characterStandingAnimationIds, String[] characterWalkingAnimationIds, String[] characterRunningAnimationIds)
    {
        this.id = characterId;
        this.name = characterName;
        this.characterStandingAnimationIds = characterStandingAnimationIds;
        this.characterWalkingAnimationIds = characterWalkingAnimationIds;
        this.characterRunningAnimationIds = characterRunningAnimationIds;

        this.characterStandingAnimations = new Animation[FieldCharacterDirection.values().length];
        this.characterWalkingAnimations = new Animation[FieldCharacterDirection.values().length];
        this.characterRunningAnimations = new Animation[FieldCharacterDirection.values().length];

        this.isBegun = false;
        this.position = new Vector2(0, 0);
        this.direction = CharacterDirection.Left;
        this.spriteDirection = FieldCharacterDirection.Side;
    }

    private Animation getCharacterStandingAnimationForDirection(FieldCharacterDirection spriteDirection)
    {
        if (this.characterStandingAnimations[spriteDirection.ordinal()] == null)
        {
            this.characterStandingAnimations[FieldCharacterDirection.Up.ordinal()] = Case.getInstance().getAnimationManager().GetAnimationFromId(this.characterStandingAnimationIds[FieldCharacterDirection.Up.ordinal()]);
            this.characterStandingAnimations[FieldCharacterDirection.DiagonalUp.ordinal()] = Case.getInstance().getAnimationManager().GetAnimationFromId(this.characterStandingAnimationIds[FieldCharacterDirection.DiagonalUp.ordinal()]);
            this.characterStandingAnimations[FieldCharacterDirection.Side.ordinal()] = Case.getInstance().getAnimationManager().GetAnimationFromId(this.characterStandingAnimationIds[FieldCharacterDirection.Side.ordinal()]);
            this.characterStandingAnimations[FieldCharacterDirection.DiagonalDown.ordinal()] = Case.getInstance().getAnimationManager().GetAnimationFromId(this.characterStandingAnimationIds[FieldCharacterDirection.DiagonalDown.ordinal()]);
            this.characterStandingAnimations[FieldCharacterDirection.Down.ordinal()] = Case.getInstance().getAnimationManager().GetAnimationFromId(this.characterStandingAnimationIds[FieldCharacterDirection.Down.ordinal()]);
        }

        return this.characterStandingAnimations[spriteDirection.ordinal()];
    }

    private Animation getCharacterWalkingAnimationForDirection(FieldCharacterDirection spriteDirection)
    {
        if (this.characterWalkingAnimations[spriteDirection.ordinal()] == null)
        {
            this.characterWalkingAnimations[FieldCharacterDirection.Up.ordinal()] = Case.getInstance().getAnimationManager().GetAnimationFromId(this.characterWalkingAnimationIds[FieldCharacterDirection.Up.ordinal()]);
            this.characterWalkingAnimations[FieldCharacterDirection.DiagonalUp.ordinal()] = Case.getInstance().getAnimationManager().GetAnimationFromId(this.characterWalkingAnimationIds[FieldCharacterDirection.DiagonalUp.ordinal()]);
            this.characterWalkingAnimations[FieldCharacterDirection.Side.ordinal()] = Case.getInstance().getAnimationManager().GetAnimationFromId(this.characterWalkingAnimationIds[FieldCharacterDirection.Side.ordinal()]);
            this.characterWalkingAnimations[FieldCharacterDirection.DiagonalDown.ordinal()] = Case.getInstance().getAnimationManager().GetAnimationFromId(this.characterWalkingAnimationIds[FieldCharacterDirection.DiagonalDown.ordinal()]);
            this.characterWalkingAnimations[FieldCharacterDirection.Down.ordinal()] = Case.getInstance().getAnimationManager().GetAnimationFromId(this.characterWalkingAnimationIds[FieldCharacterDirection.Down.ordinal()]);
        }

        return this.characterWalkingAnimations[spriteDirection.ordinal()];
    }

    private Animation getCharacterRunningAnimationForDirection(FieldCharacterDirection spriteDirection)
    {
        if (this.characterRunningAnimations[spriteDirection.ordinal()] == null)
        {
            this.characterRunningAnimations[FieldCharacterDirection.Up.ordinal()] = Case.getInstance().getAnimationManager().GetAnimationFromId(this.characterRunningAnimationIds[FieldCharacterDirection.Up.ordinal()]);
            this.characterRunningAnimations[FieldCharacterDirection.DiagonalUp.ordinal()] = Case.getInstance().getAnimationManager().GetAnimationFromId(this.characterRunningAnimationIds[FieldCharacterDirection.DiagonalUp.ordinal()]);
            this.characterRunningAnimations[FieldCharacterDirection.Side.ordinal()] = Case.getInstance().getAnimationManager().GetAnimationFromId(this.characterRunningAnimationIds[FieldCharacterDirection.Side.ordinal()]);
            this.characterRunningAnimations[FieldCharacterDirection.DiagonalDown.ordinal()] = Case.getInstance().getAnimationManager().GetAnimationFromId(this.characterRunningAnimationIds[FieldCharacterDirection.DiagonalDown.ordinal()]);
            this.characterRunningAnimations[FieldCharacterDirection.Down.ordinal()] = Case.getInstance().getAnimationManager().GetAnimationFromId(this.characterRunningAnimationIds[FieldCharacterDirection.Down.ordinal()]);
        }

        return this.characterRunningAnimations[spriteDirection.ordinal()];
    }
    
    private String id;
    
    public String getId() { return this.id; }
    
    private String name;
    
    public String getName() { return this.name; }
    
    private Vector2 position;
    
    public Vector2 getPosition() { return this.position; }
    public void setPosition(Vector2 position) { this.position = position; }
    
    private HitBox hitBox;
    
    public HitBox getHitBox() { return this.hitBox; }
    public void setHitBox(HitBox hitBox) { this.hitBox = hitBox; }
    
    private CharacterDirection direction;
    
    public CharacterDirection getDirection() { return this.direction; }
    public void setDirection(CharacterDirection direction) { this.direction = direction; }
    
    private FieldCharacterDirection spriteDirection;
    
    public FieldCharacterDirection getSpriteDirection() { return this.spriteDirection; }
    public void setSpriteDirection(FieldCharacterDirection spriteDirection)
    {
        if (spriteDirection != this.spriteDirection)
        {
            this.spriteDirection = spriteDirection;
            this.UpdateAnimation();
        }
    }
    
    private int anchorPosition;
    
    public int getAnchorPosition() { return this.anchorPosition; }
    public void setAnchorPosition(int anchorPosition) { this.anchorPosition = anchorPosition; }
    
    private Rectangle clickRect;
    
    public Rectangle getClickRect() { return this.clickRect; }
    public void setClickRect(Rectangle clickRect) { this.clickRect = clickRect; }
    
    private String clickEncounterId;
    
    public String getClickEncounterId() { return this.clickEncounterId; }
    public void setClickEncounterId(String clickEncounterId) { this.clickEncounterId = clickEncounterId; }

    public Encounter getClickEncounter()
    {
        if (this.getClickEncounterId() == null)
        {
            return null;
        }

        if (this.clickEncounter == null)
        {
            this.clickEncounter = Case.getInstance().getContent().GetEncounterFromId(this.getClickEncounterId());
        }

        return this.clickEncounter;
    }
    
    private String clickCutsceneId;
    
    public String getClickCutsceneId() { return this.clickCutsceneId; }
    public void setClickCutsceneId(String clickCutsceneId) { this.clickCutsceneId = clickCutsceneId; }

    public FieldCutscene getClickCutscene(Location owningLocation)
    {
        if (this.getClickCutsceneId() == null)
        {
            return null;
        }

        if (this.clickCutscene == null)
        {
            for (FieldCutscene locationCutscene : owningLocation.getCutsceneList())
            {
                if (locationCutscene.getId().equals(this.getClickCutsceneId()))
                {
                    this.clickCutscene = locationCutscene;
                    break;
                }
            }
        }

        return this.clickCutscene;
    }
    
    private boolean isClicked;
    
    public boolean getIsClicked() { return this.isClicked; }
    private void setIsClicked(boolean isClicked) { this.isClicked = isClicked; }

    public FieldCharacterState getState() { return this.state; }
    
    public void setState(FieldCharacterState state)
    {
        if (state != this.state)
        {
            this.InitializeAnimations(state);
            this.state = state;
            this.UpdateAnimation();
        }
    }
    
    private Vector2 interactionLocation;

    public Vector2 getInteractionLocation() { return this.interactionLocation; }
    public void setInteractionLocation(Vector2 interactionLocation) { this.interactionLocation = interactionLocation; }
    
    private boolean interactFromAnywhere;
    
    public boolean getInteractFromAnywhere() { return this.interactFromAnywhere; }
    public void setInteractFromAnywhere(boolean interactFromAnywhere) { this.interactFromAnywhere = interactFromAnywhere; }
    
    private Condition condition;
    
    public Condition getCondition() { return this.condition; }
    public void setCondition(Condition condition) { this.condition = condition; }

    public void Begin()
    {
        this.InitializeAnimations(FieldCharacterState.Standing);
        this.state = FieldCharacterState.Standing;
        
        if (this.spriteDirection == null)
        {
            this.spriteDirection = FieldCharacterDirection.Side;
        }
        
        this.UpdateAnimation();
        this.isBegun = true;
    }

    public void Update(GameContainer gc, int delta)
    {
        Rectangle adjustedClickRect = new Rectangle((int)(this.getPosition().getX() + this.getClickRect().getX()), (int)(this.getPosition().getY() + this.getClickRect().getY() - this.extraHeight), this.getClickRect().getWidth(), this.getClickRect().getHeight());
        this.Update(gc, delta, adjustedClickRect);
    }

    public void Update(GameContainer gc, int delta, Vector2 offsetVector)
    {
        Rectangle adjustedClickRect = new Rectangle((int)(this.getPosition().getX() - offsetVector.getX() + this.getClickRect().getX()), (int)(this.getPosition().getY() - offsetVector.getY() + this.getClickRect().getY() - this.extraHeight), this.getClickRect().getWidth(), this.getClickRect().getHeight());
        this.Update(gc, delta, adjustedClickRect);
    }

    public void Update(GameContainer gc, int delta, Rectangle adjustedClickRect)
    {
        if (!this.isBegun)
        {
            this.Begin();
        }

        if (this.state == FieldCharacterState.Standing)
        {
            this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.Up).Update(gc, delta);
            this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.DiagonalUp).Update(gc, delta);
            this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.Side).Update(gc, delta);
            this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.DiagonalDown).Update(gc, delta);
            this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.Down).Update(gc, delta);
        }
        else if (this.state == FieldCharacterState.Walking)
        {
            this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.Up).Update(gc, delta);
            this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.DiagonalUp).Update(gc, delta);
            this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.Side).Update(gc, delta);
            this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.DiagonalDown).Update(gc, delta);
            this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.Down).Update(gc, delta);
        }

        if (this.getClickEncounter() != null && (MouseHelper.MouseOverRect(adjustedClickRect) || MouseHelper.MouseDownOnRect(adjustedClickRect)))
        {
            MouseHelper.SetToHandCursor();
        }

        this.setIsClicked(MouseHelper.ClickedOnRect(adjustedClickRect));
    }

    public void Draw(GameContainer gc, Graphics g)
    {
        this.currentAnimation.Draw(gc, g, this.getPosition().subtract(new Vector2(0, this.extraHeight)), this.getDirection() == CharacterDirection.Right, 1.0f);
    }
    
    public void Draw(GameContainer gc, Graphics g, Vector2 offsetVector)
    {
        this.currentAnimation.Draw(gc, g, this.getPosition().subtract(offsetVector).subtract(new Vector2(0, this.extraHeight)), this.getDirection() == CharacterDirection.Right, 1.0f);
    }

    public void Reset()
    {
        this.ResetAnimations();
        this.currentAnimation = null;
        this.setIsClicked(false);
        this.isBegun = false;
    }
    
    public void Reset(CharacterDirection direction, FieldCharacterDirection spriteDirection, Vector2 position, FieldCharacterState state)
    {
        this.direction = direction;
        this.spriteDirection = spriteDirection;
        this.position = position;
        this.state = state;
    }
    
    public Vector2 GetAnchorPosition()
    {
        return new Vector2(
                this.getPosition().getX() + this.getClickRect().getX() + this.getClickRect().getWidth() / 2,
                this.getPosition().getY() + this.getAnchorPosition());
    }
    
    public Vector2 GetMidPoint()
    {
        return new Vector2(
                this.getPosition().getX() + this.getClickRect().getX() + this.getClickRect().getWidth() / 2,
                this.getPosition().getY() + this.getClickRect().getY() + this.getClickRect().getHeight() / 2 - this.extraHeight);
    }

    public Vector2 GetCenterPoint()
    {
        return this.GetAnchorPosition();
    }
    
    public int GetExtraHeight()
    {
        return this.extraHeight;
    }
    
    public void SetExtraHeightFromHeightMaps(ArrayList<HeightMap> heightMapList)
    {
        this.extraHeight = 0;
        Vector2 characterPosition = this.GetAnchorPosition();
        
        for (int i = 0; i < heightMapList.size(); i++)
        {
            HeightMap heightMap = heightMapList.get(i);
            
            if (heightMap.IsPointInBoundingPolygon(characterPosition))
            {
                this.extraHeight += heightMapList.get(i).GetHeightAtPoint(characterPosition);
            }
        }
    }

    public Rectangle GetBoundsForInteraction()
    {
        Rectangle hitboxBoundingBox = this.getHitBox().GetBoundingBox();
        
        return new Rectangle(
                (float)this.GetAnchorPosition().getX() + hitboxBoundingBox.getX(),
                (float)this.GetAnchorPosition().getY() + hitboxBoundingBox.getY(),
                hitboxBoundingBox.getWidth(),
                hitboxBoundingBox.getHeight());
    }

    public void BeginInteraction(Location location)
    {
        location.BeginCharacterEncounter(this);
    }
    
    public void SetPositionByAnchorPosition(Vector2 targetPosition)
    {
        this.setPosition(this.getPosition().add(targetPosition.subtract(this.GetAnchorPosition())));
    }

    public boolean IsCollision(FieldCharacter character, CollisionParameter param)
    {
        return this.getHitBox().IsCollision(this.getPosition(), character.getHitBox(), character.getPosition(), param);
    }

    public boolean IsCollision(HitBox hitBox, CollisionParameter param)
    {
        return this.getHitBox().IsCollision(this.getPosition(), hitBox, new Vector2(0, 0), param);
    }

    public boolean TestCollisionAtPosition(Vector2 position, FieldCharacter character, CollisionParameter param)
    {
        return this.getHitBox().IsCollision(position, character.getHitBox(), character.getPosition(), param);
    }

    public boolean TestCollisionAtPosition(Vector2 position, HitBox hitBox, CollisionParameter param)
    {
        return this.getHitBox().IsCollision(position, hitBox, new Vector2(0, 0), param);
    }

    public FieldCharacter Clone()
    {
        FieldCharacter cloneCharacter = new FieldCharacter(this.getId(), this.getName(), this.characterStandingAnimationIds, this.characterWalkingAnimationIds, this.characterRunningAnimationIds);
        cloneCharacter.setHitBox(this.getHitBox());
        cloneCharacter.setAnchorPosition(this.getAnchorPosition());
        cloneCharacter.setClickRect(this.getClickRect());
        cloneCharacter.setInteractionLocation(this.interactionLocation);
        cloneCharacter.setInteractFromAnywhere(this.interactFromAnywhere);
        cloneCharacter.setCondition(this.condition != null ? this.condition.Clone() : null);
        return cloneCharacter;
    }
    
    private void InitializeAnimations(FieldCharacterState newState)
    {
        if (this.state != newState)
        {
            if (this.state == FieldCharacterState.Standing)
            {
                this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.Up).Reset();
                this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.DiagonalUp).Reset();
                this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.Side).Reset();
                this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.DiagonalDown).Reset();
                this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.Down).Reset();
            }
            else if (this.state == FieldCharacterState.Walking)
            {
                this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.Up).Reset();
                this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.DiagonalUp).Reset();
                this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.Side).Reset();
                this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.DiagonalDown).Reset();
                this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.Down).Reset();
            }
            
            if (newState == FieldCharacterState.Standing)
            {
                this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.Up).Begin();
                this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.DiagonalUp).Begin();
                this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.Side).Begin();
                this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.DiagonalDown).Begin();
                this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.Down).Begin();
            }
            else if (newState == FieldCharacterState.Walking)
            {
                this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.Up).Begin();
                this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.DiagonalUp).Begin();
                this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.Side).Begin();
                this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.DiagonalDown).Begin();
                this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.Down).Begin();
            }
        }
    }
    
    private void UpdateAnimation()
    {
        if (this.state == FieldCharacterState.Standing)
        {
            this.currentAnimation = this.getCharacterStandingAnimationForDirection(this.spriteDirection);
        }
        else if (this.state == FieldCharacterState.Walking)
        {
            this.currentAnimation = this.getCharacterWalkingAnimationForDirection(this.spriteDirection);
        }
    }
    
    private void ResetAnimations()
    {
        if (this.state == FieldCharacterState.Standing)
        {
            this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.Up).Reset();
            this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.DiagonalUp).Reset();
            this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.Side).Reset();
            this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.DiagonalDown).Reset();
            this.getCharacterStandingAnimationForDirection(FieldCharacterDirection.Down).Reset();
        }
        else if (this.state == FieldCharacterState.Walking)
        {
            this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.Up).Reset();
            this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.DiagonalUp).Reset();
            this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.Side).Reset();
            this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.DiagonalDown).Reset();
            this.getCharacterWalkingAnimationForDirection(FieldCharacterDirection.Down).Reset();
        }
    }
    
    public int GetZOrder()
    {
        if (this.anchorPosition >= 0)
        {
            return (int)this.position.getY() + this.anchorPosition;
        }
        else
        {
            return -1;
        }
    }

    public boolean IsVisible()
    {
        return true;
    }

    public mylittleinvestigations.Line GetZOrderLine()
    {
        return null;
    }

    public Vector2 GetZOrderPoint()
    {
        return this.GetAnchorPosition();
    }

    public void SaveToXml(CaseXmlWriter writer) throws IOException
    {
        writer.StartElement("FieldCharacter");
        writer.WriteTextElement("Id", this.id);
        writer.WriteTextElement("Name", this.name);
        
        writer.StartElement("CharacterStandingAnimationIds");
        
        writer.StartElement("Entry");
        writer.WriteTextElement("Direction", FieldCharacterDirection.Up.name());
        writer.WriteTextElement("Id", this.characterStandingAnimationIds[FieldCharacterDirection.Up.ordinal()]);
        writer.EndElement();
        
        writer.StartElement("Entry");
        writer.WriteTextElement("Direction", FieldCharacterDirection.DiagonalUp.name());
        writer.WriteTextElement("Id", this.characterStandingAnimationIds[FieldCharacterDirection.DiagonalUp.ordinal()]);
        writer.EndElement();
        
        writer.StartElement("Entry");
        writer.WriteTextElement("Direction", FieldCharacterDirection.Side.name());
        writer.WriteTextElement("Id", this.characterStandingAnimationIds[FieldCharacterDirection.Side.ordinal()]);
        writer.EndElement();
        
        writer.StartElement("Entry");
        writer.WriteTextElement("Direction", FieldCharacterDirection.DiagonalDown.name());
        writer.WriteTextElement("Id", this.characterStandingAnimationIds[FieldCharacterDirection.DiagonalDown.ordinal()]);
        writer.EndElement();
        
        writer.StartElement("Entry");
        writer.WriteTextElement("Direction", FieldCharacterDirection.Down.name());
        writer.WriteTextElement("Id", this.characterStandingAnimationIds[FieldCharacterDirection.Down.ordinal()]);
        writer.EndElement();
        
        writer.EndElement();
        
        writer.StartElement("CharacterWalkingAnimationIds");
        
        writer.StartElement("Entry");
        writer.WriteTextElement("Direction", FieldCharacterDirection.Up.name());
        writer.WriteTextElement("Id", this.characterWalkingAnimationIds[FieldCharacterDirection.Up.ordinal()]);
        writer.EndElement();
        
        writer.StartElement("Entry");
        writer.WriteTextElement("Direction", FieldCharacterDirection.DiagonalUp.name());
        writer.WriteTextElement("Id", this.characterWalkingAnimationIds[FieldCharacterDirection.DiagonalUp.ordinal()]);
        writer.EndElement();
        
        writer.StartElement("Entry");
        writer.WriteTextElement("Direction", FieldCharacterDirection.Side.name());
        writer.WriteTextElement("Id", this.characterWalkingAnimationIds[FieldCharacterDirection.Side.ordinal()]);
        writer.EndElement();
        
        writer.StartElement("Entry");
        writer.WriteTextElement("Direction", FieldCharacterDirection.DiagonalDown.name());
        writer.WriteTextElement("Id", this.characterWalkingAnimationIds[FieldCharacterDirection.DiagonalDown.ordinal()]);
        writer.EndElement();
        
        writer.StartElement("Entry");
        writer.WriteTextElement("Direction", FieldCharacterDirection.Down.name());
        writer.WriteTextElement("Id", this.characterWalkingAnimationIds[FieldCharacterDirection.Down.ordinal()]);
        writer.EndElement();
        
        writer.EndElement();
        
        writer.StartElement("CharacterRunningAnimationIds");
        
        writer.StartElement("Entry");
        writer.WriteTextElement("Direction", FieldCharacterDirection.Up.name());
        writer.WriteTextElement("Id", this.characterRunningAnimationIds[FieldCharacterDirection.Up.ordinal()]);
        writer.EndElement();
        
        writer.StartElement("Entry");
        writer.WriteTextElement("Direction", FieldCharacterDirection.DiagonalUp.name());
        writer.WriteTextElement("Id", this.characterRunningAnimationIds[FieldCharacterDirection.DiagonalUp.ordinal()]);
        writer.EndElement();
        
        writer.StartElement("Entry");
        writer.WriteTextElement("Direction", FieldCharacterDirection.Side.name());
        writer.WriteTextElement("Id", this.characterRunningAnimationIds[FieldCharacterDirection.Side.ordinal()]);
        writer.EndElement();
        
        writer.StartElement("Entry");
        writer.WriteTextElement("Direction", FieldCharacterDirection.DiagonalDown.name());
        writer.WriteTextElement("Id", this.characterRunningAnimationIds[FieldCharacterDirection.DiagonalDown.ordinal()]);
        writer.EndElement();
        
        writer.StartElement("Entry");
        writer.WriteTextElement("Direction", FieldCharacterDirection.Down.name());
        writer.WriteTextElement("Id", this.characterRunningAnimationIds[FieldCharacterDirection.Down.ordinal()]);
        writer.EndElement();
        
        writer.EndElement();
        
        writer.StartElement("Position");
        this.position.SaveToXml(writer);
        writer.EndElement();
        
        this.hitBox.SaveToXml(writer);
        writer.WriteTextElement("Direction", this.direction.name());
        writer.WriteTextElement("SpriteDirection", this.spriteDirection.name());
        writer.WriteIntElement("AnchorPosition", this.anchorPosition);
        
        writer.StartElement("ClickRect");
        writer.WriteRectangleElement(this.clickRect);
        writer.EndElement();
        
        if (this.clickEncounterId != null)
        {
            writer.WriteTextElement("ClickEncounterId", this.clickEncounterId);
        }
        
        if (this.clickCutsceneId != null)
        {
            writer.WriteTextElement("ClickCutsceneId", this.clickCutsceneId);
        }
        
        if (this.interactionLocation != null)
        {
            writer.StartElement("InteractionLocation");
            this.interactionLocation.SaveToXml(writer);
            writer.EndElement();
        }
            
        writer.WriteBooleanElement("InteractFromAnywhere", this.interactFromAnywhere);
            
        if (this.condition != null)
        {
            writer.StartElement("Condition");
            this.condition.SaveToXml(writer);
            writer.EndElement();
        }
        
        writer.EndElement();
    }

    public FieldCharacter(CaseXmlReader reader)
    {
        this.characterStandingAnimationIds = new String[FieldCharacterDirection.values().length];
        this.characterWalkingAnimationIds = new String[FieldCharacterDirection.values().length];
        
        this.characterStandingAnimations = new Animation[FieldCharacterDirection.values().length];
        this.characterWalkingAnimations = new Animation[FieldCharacterDirection.values().length];

        this.isBegun = false;
        this.position = new Vector2(0, 0);
        this.direction = CharacterDirection.Left;
        
        reader.StartElement("FieldCharacter");
        this.id = reader.ReadTextElement("Id");
        this.name = reader.ReadTextElement("Name");
        
        reader.StartElement("CharacterStandingAnimationIds");
        reader.StartList("Entry");
        
        while (reader.MoveToNextListItem())
        {
            FieldCharacterDirection direction = FieldCharacterDirection.valueOf(reader.ReadTextElement("Direction"));
            this.characterStandingAnimationIds[direction.ordinal()] = reader.ReadTextElement("Id");
        }
        
        reader.EndElement();
        
        reader.StartElement("CharacterWalkingAnimationIds");
        reader.StartList("Entry");
        
        while (reader.MoveToNextListItem())
        {
            FieldCharacterDirection direction = FieldCharacterDirection.valueOf(reader.ReadTextElement("Direction"));
            this.characterWalkingAnimationIds[direction.ordinal()] = reader.ReadTextElement("Id");
        }
        
        reader.EndElement();
        
        reader.StartElement("CharacterRunningAnimationIds");
        reader.StartList("Entry");
        
        while (reader.MoveToNextListItem())
        {
            FieldCharacterDirection direction = FieldCharacterDirection.valueOf(reader.ReadTextElement("Direction"));
            this.characterRunningAnimationIds[direction.ordinal()] = reader.ReadTextElement("Id");
        }
        
        reader.EndElement();
        
        reader.StartElement("Position");
        this.position = new Vector2(reader);
        reader.EndElement();
        
        this.hitBox = new HitBox(reader);
        this.direction = CharacterDirection.valueOf(reader.ReadTextElement("Direction"));
        this.spriteDirection = FieldCharacterDirection.valueOf(reader.ReadTextElement("SpriteDirection"));
        this.anchorPosition = reader.ReadIntElement("AnchorPosition");
        
        reader.StartElement("ClickRect");
        this.clickRect = reader.ReadRectangleElement();
        reader.EndElement();
        
        if (reader.ElementExists("ClickEncounterId"))
        {
            this.clickEncounterId = reader.ReadTextElement("ClickEncounterId");
        }
        
        if (reader.ElementExists("ClickCutsceneId"))
        {
            this.clickCutsceneId = reader.ReadTextElement("ClickCutsceneId");
        }
        
        reader.EndElement();
    }
    
    public void markChildSprites(String markParent, FieldCharacterState state, FieldCharacterDirection direction)
    {
        String[] animationIds = null;
        System.out.println("Now marking character " + this.getName() + " for state " + state.name() + " and direction " + direction.name());
        
        if (state == FieldCharacterState.Standing)
        {
            animationIds = this.characterStandingAnimationIds;
        }
        else if (state == FieldCharacterState.Walking)
        {
            animationIds = this.characterWalkingAnimationIds;
        }
        else if (state == FieldCharacterState.Running)
        {
            animationIds = this.characterRunningAnimationIds;
        }
        
        Case.getInstance().getAnimationManager().GetAnimationFromId(animationIds[direction.ordinal()]).markChildSprites(markParent);
        /*for (String a : characterStandingAnimationIds)
        {
            Case.getInstance().getAnimationManager().GetAnimationFromId(a).markChildSprites(markParent);
        }
        for (String a : characterWalkingAnimationIds)
        {
            Case.getInstance().getAnimationManager().GetAnimationFromId(a).markChildSprites(markParent);
        }
        for (String a : characterRunningAnimationIds)
        {
            Case.getInstance().getAnimationManager().GetAnimationFromId(a).markChildSprites(markParent);
        }
        if (this.getClickEncounter() != null)
        {
            try
            {
                this.getClickEncounter().markChildSprites(markParent);
            }
            catch (CaseParseException ex)
            {
                Logger.getLogger(FieldCharacter.class.getName()).log(Level.SEVERE, null, ex);
            }
        }*/
    }
    
    public void markChildEncounterSprites(String markParent) throws CaseParseException
    {
        if (this.getClickEncounter() != null)
        {
            this.getClickEncounter().markChildSprites(markParent);
        }
    }
}
